ゆるふわシェル問題 その1
全部で8問
そんなに難しくないはず
だいたい1コマンドで解ける
使う技術
問題
Q1. 以下のテキストファイルaに含まれる犬郎を太郎に直せ
code:a
山田犬郎
犬神健一
藤崎宗犬郎
問題の意図
sedを使う
犬を太に変換するだけだと犬神さんも書き換わっちゃう点に注意する
trだとマルチバイト文字の置換がうまくいかない
答え
code:q1.sh
sed "s/犬郎/太郎/g" a
Q2 カレンダーの曜日、毎日休みがいいので月から金まで日曜日にしてください。
code:cal
2月 2020
日 月 火 水 木 金 土
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
問題の意図
複数の文字をsedで置換する
sedのyコマンドか正規表現を使うのが簡単かなぁと思ってる
答え
code:q2_1.sh
cal | sed '2y/月火水木金/日日日日日/'
解説
yは置換対象と置換後を1文字ずつ対応して置換する
上のだと月は1文字目の日と対応して置換される
code:q2_2.sh
cal | sed -E '2s/月火水木金/日/g' 解説
-Eで拡張正規表現を有効にする
[月火水木金]は月火水木金のいずれかの文字にマッチする
日でいずれかにマッチしたものを日に置換する
末尾のgは行内でマッチするすべてを置換する
これがないと月だけ置換して終わる
追記
2s///gみたいに先頭に2って付けないと1行目の2月まで置換されてしまっていた
Q3 以下のテキストファイルaから山田太郎さんを抽出してください。表記のムラも考慮してください
code:a
山崎太郎
山田太郎
ヤマダタロウ
山田たろう
山田 太郎
山田 太郎
山本太郎
山田一郎
問題の意図
単純にgrepするだけだとどれかを取りこぼすか余計なものが交じる
どうやって複数のテキストを抽出するか
答え
code:q3.sh
grep -E "(山田|ヤマダ)( | )?(太郎|タロウ|たろう)" a
解説
-Eで拡張正規表現を有効にする
(山田|ヤマダ)では山田かヤマダにマッチする
( | )では半角スペースか全角スペースにマッチする
?では直前の文字が1つ存在する場合としない場合にマッチする
(太郎|タロウ|たろう)で太郎かタロウかたろうにマッチする
Q4 以下のCSVファイル(大嘘)の2列めを取り出してください
code:a
ID、名前、趣味
1、田中、野球
2、山本、サッカー
3、鈴木、バレー
問題の意図
cutではマルチバイト文字を区切り文字に指定できない
awkを使う必要がある
答え
code:q4.sh
awk -F 、 '{print $2}' a
解説
-F、で区切り文字に、を指定
$2で2列目の文字を指定
Q5 以下の点数表の平均値を求めてください
code:a
name,score
田中,89
山田,60
鈴木,75
村田,95
問題の意図
awkで簡単な集計をする
平均値なので合計値を全体数で割る時に工夫が必要
awkのNR変数を割る時の全体数に使うとヘッダの行数も含まれてるので1引く必要がある
答え
code:q5.sh
awk -F , '{ total += $2 } END { print total / (NR-1) }' a
79.75
この辺の解説はawkでググればいっぱいヒットするのでそっちで見て(なげっぱなし)
Q6 echoを使わずに寿司と標準出力してください
問題の意図
なんとなく
他の人はどういうアプローチするかなぁというのが気になっただけ
答え
code:q6.sh
cat <<< 寿司
Q7 以下のような階段状の文字列を出力してください
ヒアストリングはNGで!
code:a
1
11
111
1111
11111
111111
問題の意図
繰り返し処理をどうやるか
awkを使うのが一般的かなぁと思ってたけれどforでもできると思う
答え
code:q7.sh
seq 6 | awk '{ s = ""; for (i=0; i<NR; i++) { s = s "1" } print s }'
Q8. /work ディレクトリの下に2019/01 〜 2020/12までのディレクトリを作成してください。月はサブディレクトリを切ってください
問題の意図
実務ですぐ使えるシェルが役立つシーンの一つだと思ってだした
ループ処理をどうやるか
mkdirのオプションを知っているか
答え
code:q8.sh
mkdir -p /work/20{19,20}/{01..12}
解説
-pで存在しない親ディレクトリごと一気に作成できる
{}でブレース展開
{19,20}は19と20の文字列を半角スペース区切りで作る
{01..12}は01から12の文字列を半角スペース区切りで作る
これらのブレース展開はブレース展開と隣接する文字を合わせて展開する
例
code:sh
echo a_{01..12}
# a_01 a_02 a_03 a_04 a_05 a_06 a_07 a_08 a_09 a_10 a_11 a_12
これをそのままtouchすれば空ファイルが作れる
mkdirすればディレクトリが作れる
以上
余談
問題考えるの難しい!!!
cat, grep, sed, awk, 正規表現とメジャーどころは抑えた気がする
sort, uniqもよく使うけれど簡単な問題が思いつかなかった
forやwhile使うやつもあってよかったかなぁ
cut, join, trとかはチョット考えたけどお見送り
joinはオプション自体が複雑だしなぁ〜〜〜
実務オペレーションでよく使うコマンドとかで問題だしてみたいなぁ
nginxのアクセスログの調査とか
件数集計とソートとか
圧縮ファイルの操作とか
ファイルの探し方とか
trapとか
バックグラウンド処理と
日付処理とか
ファイル作成とか
ダミーファイル作成とか
なんかLPICの問題みたいだな・・・